<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <a href="../index.html"></a>
    <a href="./ide编辑器.html"></a>
</body>
<script>
/* 
    安装环境
        jdk
        jre jdk1.5以后自带jre
    环境安装
        JAVA_HOME
        D:\Java\jdk-9.0.4
        Path
        追加 %JAVA_HOME%\bin

    double  1.2  1.2d  1.2D
    float  1.2f  1.2F
    长字节可以容纳短字节型
    运算符
        分子分母都为整型时，结果为整除后的结果
        13/5  ==>  2
        13.0/5  ==>  2.6
    键盘输入
        Scanner s = new Scanner(System.in)
        int n = s.nextInt()  接收整数
        String n = s.next() 接收字符串

    集合
        声明
            ArrayList<Integer> redList = new ArrayList<>()
        添加
            redList.add(1)
        删除(删除某下标上的值 返回被删除的值)
            int index = 0
            redList.remove(index)

    逻辑运算符
        && 短路 如果一个为false剩下的不执行
        &不短路
        ||短路 如果一个为true 剩下的不执行
        |不短路
        布尔值不可以跟整型进行判断

    while循环
        int n = 1;
        while(n<5){
            n++;
        }

    do-while
        至少执行一次
        尾部分号不能丢
        int n = 1;
        do{
            n++
        }while(n<5);

    二维数组
        int[][] intArray = new[3][5]; //3 行5列动态数组
        int[][] inArray = {{1,2,3},{1,2}, {1,2,3}}; //静态数组
        行数必须指定

    增强型for foreach
        int[] arr1 = {1, 2, 3, 4};//一维 
        for(int item:arr1){
            item
        }
        int[][] arr2 = {{1,2},{1,2},{1,2}};//二维
        for(int[] item:arr){
            item
        }

    可变参数
        可变参数必须在最后一位
        可变参数可以接收数组
        数组不可以接收可变参数
        所在的方法最后被访问
        public void Arg(int a, int... n){

        }
        int n = 1
        int[] arr = {1,2,3,4,5}
        Arg(n, arr)

    文档注释
        javadoc -d doc Demo.java

    类
    构造函数
        没有返回值类型
        无参构造
        名字必须与类相同
        只会在实例化时别直接调用
        在构造方法中如果使用this调用其他构造方法，只能是第一条语句
    实例化
        声明 Cat one
        实例化 new Cat()
        
    方法
        注意事项
            1.方法应该定义在类当中，但是不能在方法当中再定义方法。不能嵌套
            2.如果方法有返回值，那么必须写上return 返回值
            3.return后面的返回值数据，必须和方法的返回值类型对应
            4.对于一个void没有返回值的方法，不能写return后面的返回值，只能写return
            5.对于void方法当中最后一行的return可以不写
            6.一个方法必须保证同时只有一个会被执行到
        格式：
        访问修饰符 返回值类型 方法名（参数列表）{
            方法体
        }
        类 对象 = new 类();
        对象.方法();

        有返回值
        public static int fn( int a,int b ){
            return
        }

    方法重载
        与下列因素相关
            1.参数个数
            2.参数类型
            3.参数的多类型顺序不同
        与下列因素无关
            1.与参数名称无关
            2.与方法的返回值类型无关

    数组
        注意事项：使用动态初始化数组的时候，其中的元素将会自动拥有默认值
            整数类型，默认为0
            浮点类型，默认为0.0
            字符类型，默认为'\u0000'
            布尔类型，默认为false
            引用类型，默认为null
        长度一旦定义就不能改变了
        动态初始化格式
            数据类型[] 数组名称 = new 数据类型[数组长度]
        静态初始化格式
            数据类型[] 数组名称 = new 数据类型[] {元素1, 元素2, ...}
            数据类型[] 数组名称 = {元素1, 元素2, ...}
        int[] intArray = new int[5]; // 动态
        int[] arr = {1,2,3,4}; // 静态
        
        // Arrays.toString()
    面向对象
        面向过程：强调过程
        面向对象：强调对象
        1.封装性
        2.继承性
        3.多态性
        通常情况下，一个类并不能直接使用，需要根据类创建一个对象，才能使用
        1.导包：也就是指出需要使用的类，在什么位置。
            import 包名称.类名称;
            import cn.itcast.day06.demo01.Student;
            对于和当前类属于同一个包的情况，可以省略导包语句不写。
        2.创建，格式：
            类名称 对象名 = new 类名称();
            Student stu = new Student();
        3.使用，分为两种情况
            使用成员变量：对象名.成员变量名
            使用成员方法：对象名.成员方法名(参数)
            （也就是，想用谁，就用对象名点儿谁。）
        注意事项：
            如果成员变量没有进行赋值，那么将会有一个默认值，规则和数组一样。
    
    封装
        private
            setXxx getXxx
        对于基本类型的boolean,Getter方法一定要写成isXxx,而setXxx规则不变
    构造方法
        是专门用来创造对象的方法，当我们通过关键字new来创建对象时，其实就是在调用构造方法
        格式
            public 类名称(参数类型 参数名称){
                方法体
            }
        注意事项
            1.构造方法的名称必须和所在的类名称完全一样，就连大小写也要一样
            2.构造方法不要写返回值类型，就连void都不写
    继承
        定义父类（一个普通的类定义）
            public class 父类名称 {
                
            }
            public class 子类名称 extends 父类名称 {
                ...
            }
    继承中的方法覆盖重写
        public class Phone{
            public void show(){
                System.out.println("显示号码");
            }
        }
        public class NewPhone extends Phone{
            @Override
            public void show(){//覆盖重写父级的show方法
                super.show() //调用父级的原方法
                System.out.println("显示姓名")
            }
        }
        public class Demo{
            public static main(String[] args){
                Phone phone = new Phone()
                phone.show();//显示号码

                NewPhone newPhone = new NewPhone()
                newPhone.show();//显示号码 显示姓名
            }
        }
    区分子类方法中变量重名
        变量 优先选局部
        this.变量名 成员变量
        super.变量名 父类的成员变量
    重写（Override）
        概念：在继承关系当中，方法的名称一样，参数列表也一样
            重写（Override）方法的名称一样，参数列表也一样
            重载（Overload）方法的名称一样，参数列表不一样
        注意事项
            1.必须保证父子类之间方法的名称相同，参数列表也相同
              @Override：写在方法前面，用来检测是不是有效的正确覆盖重写
              这个注解就算不写，只要满足要求，也是正确的方法覆盖重写
            2.子类方法的返回值必须【小于等于】父类方法的返回值范围
              小扩展提示：java.lang.Object类是所有类的公共最高父类（祖宗类），java.lang.String就算Object的子类
            3.子类方法的权限必须【大于等于】父类方法的权限修饰符
              小扩展提示：public > protected > (default) > private
              备注：(default)不是关键字default，而是什么都不写，留空
            4.大多数用到的返回值和权限都是相等的
        例子
            @Override
            public void method(){

            }
    构造方法
        继承关系中，父子类构造方法的访问特点：
            1.子类构造方法当中有一个默认隐含的“super()”调用，所有一定是先调用的父类构造，后执行的子类构造
            2.可以通过super关键字来子类构造调用父类重载构造
            3.super的父类构造调用，必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造
        总结：子类必须调用父类的构造方法，不写则赠送super()；写了则用写的指定的super调用。super只能有一个，还是第一个
        例子
            public class Fu {
                public Fu(){
                    System.out.println("父类构造方法！")
                }
            }
            public class Zi extends Fu{
                public Zi(){
                    System.out.println("子类构造方法！")
                }
            }
            public static void main(String[] args){
                Zi zi = new Zi() //父类构造方法！ 子类构造方法！
            }
    super关键字的用法有三种：
        1.在子类的成员方法中，访问父类的成员变量
        2.在子类的成员方法中，访问父类的成员方法
        3.在子类的构造方法中，访问父类的构造方法
        例子
            public class Fu{
                int num = 10
                public method(){
                    System.out.println("父类方法！");
                }
            }
            public class Zi extends Fu{
                int num = 20
                public Zi(){
                    super();
                }
                public void methodZi(){
                    System.out.println(super.num);//父类的num
                }
                public void method(){
                    super.method();//访问父类的method
                    System.out.println("子类方法！");
                }
            }
            public static void main(String[] args){
                Zi zi = new Zi()
                zi.method();//10
                zi.methodZi();//父类方法！子类方法！
            }
    this
        super关键字用来访问父类内容，this关键字用来访问本类内容
        1.在本类的成员方法中，访问本类的成员变量
        2.在本类的成员方法中，访问本类的另一个成员方法
        3.在本类的构造方法中，访问本类的另一个构造方法
        在第三种方法当中注意：
        A.this(...)调用也是必须是构造方法的第一个语句，唯一一个
        B.super和this两种构造调用，不能同时使用
        例子
            public class Zi{
                int num = 20
                public Zi(){
                    this(123)//本类的无参构造,调用本类的有参构造
                }
                public Zi(int n){
                    this(1, 2)
                }
                public Zi(int n, m){
                    // this() 无参调1个参数的  1个调2个的  2个再调无参的(死循环程序会报错)
                }
                public void methodAA(){
                    methodBB()// 和 this.methodBB()一样
                }
                public void methodBB(){

                }
            }
    Java继承的3个特点
        Java语言是单继承的,一个类的直接父类只能有一个
            class A{}
            class B extends A{}//正确
            class C{}
            class D extends A,C{}//错误
        Java语言可以多级继承
            class A{}
            class B extends A{}
            class C extends B{}
            最上层的类的java.lang.Object
        一个类直接父类是唯一的,但是一个父类可以拥有多个子类
            class A{}
            class B extends A{}//正确
            class C extends A{}//正确
    抽象
        抽象方法：就是加上abstract关键字，然后去掉大括号，直接分号结束
        抽象类：抽象方法所在的类，必须是抽象类才行。在class之前写上abstract基类
        如何使用抽象类和抽象方法：
            1.不能直接创建new抽象类对象
            2.必须用一个子类来继承抽象父类
            3.子类必须覆盖重写抽象父类当中所有的抽象方法
              覆盖重写（实现）：子类去掉抽象方法的abstract关键字，然后补上方法体大括号
            4.创建子类对象进行使用
            5.一个抽象类不一定含有抽象方法：
             只要保证抽象方法所在的类是抽象类，即可
             这样没有抽象方法的抽象类，也不能直接创建对象，在一些特殊场景下有用途
             public abstract class MyAbstract {}
        注意事项
            抽象类不能创建对象,如果创建,编译无法通过而报错，只能创建其非抽象子类的对象
                理解：假设创建了抽象类的对象,调用抽象类的方法,而抽象类的方法没有具体的方法体,没有意义
            抽象类中可以有构造方法,是供子类创建对象时，初始化父类成员使用的
                理解：子类的构造方法中，有默认的super()，需要访问父类构造方法
            抽象类中，不一定包含抽象方法，但是有抽象方法的类必定是抽象类
                理解：未包含抽象方法的抽象类，目的就是不想让调用者创建该类对象，通常用于某些特殊的类结构设计
            抽象类的子类，必须重写抽象父类中的所有抽象方法，否则，编译无法通过而报错，除非该子类也是抽象类
                理解：假设不重写所有抽象方法，则类中可能包含抽象方法。那么创建对象后，调用抽象的方法，没有意义
        例子
            public abstract class Animal{//抽象类
                public abstract void eat();//抽象方法
                public abstract void sleep();//抽象方法
                public void normalMethod(){}//普通方法
            }
            public abstract class Dog extends Animal{
                @Override
                public void eat(){
                    System.out.println("吃骨头");
                }
                // public void sleep(){}
            }
            public class Dog2Ha extends Dog{
                @Override
                public void sleep(){
                    System.out.println("嘿嘿嘿...");
                }
            }
            public class DogJm extends Dog{
                @Override
                public void sleep(){
                    System.out.println("呼呼呼...");
                }
            }
            public static void main(String[] args){
                Dog2Ha dog2Ha = new Dog2Ha()
                dog2ha.eat();//吃骨头
                dog2ha.sleep();//嘿嘿嘿...

                DogJm dogJm = new DogJm()
                dogJm.eat();//吃骨头
                dogJm.sleep();//呼呼呼...
            }
    接口
        接口就是多个类的公共规范
        接口是引用数据类型，最重要的内容是抽象方法
        定义接口的格式
            public interface 接口名称 {
                接口内容
            }
        备注：换成了关键字interface之后，编译生成的字节码文件仍然是：.java --> .class
            如果是Java7，那么接口中包含的内容有：
                1.常量
                2.抽象方法
            如果是Java8，还可以额外包含有：
                3.默认方法
                4.静态方法
            如果是Java9，还可以额外包含有：
                5.私有方法
        接口使用步骤
            1.接口不能直接使用，必须有一个“实现类”来“实现”该接口
            格式：
                public class 实现类名称 implements 接口名称 {
                    ...
                }
            2.接口的实现类必须覆盖重写（实现）接口中所有的抽象方法
            实现：去掉abstract关键字，加上方法体大括号
            3.创建实现类的对象，进行使用
        注意事项：
            1.接口当中的抽象方法，修饰符必须是两个固定的关键字：public abstract
            2.这两个关键字修饰符，可以选择性的省略
                例:
                    public interface MyInterfaceAbstract{
                        public abstract void methodsAbs();
                        abstract void methodsAbs1();
                        public void methodsAbs2();
                        void methodsAbs3();
                    }
            3.如果实现类并没有覆盖重写所有的抽象方法，那么这个实现类自己就必须是抽象类
    默认方法
        从Java 8开始接口里允许定义默认方法
        public default 返回值类型 方法名称(参数列表){
            方法体
        }
        接口当中的默认方法，可以解决接口升级的问题
        1.接口的默认方法，可以通过接口实现类对象，直接调用
        2.接口的默认方法，也可以被实现类进行覆盖重写
        例：
            public interface MyInterfaceDefault{
                public abstract void methodAbs();//必须覆盖重写
                public default void methodAbsDefault(){//可选覆盖重写
                    System.out.println("这是新添加的默认方法");
                }
            }
            public class MyInterfaceDefaultA implements MyInterfaceDefault{
                @Override
                public void methodAbs(){
                    System.out.println("实现了抽象方法，方法AAA");
                }
            }
            public class MyInterfaceDefaultB implements MyInterfaceDefault{
                @Override
                public void methodAbs(){
                    System.out.println("方法BBB");
                }
                @Override
                public void methodAbsDefault(){
                    System.out.println("实现类B覆盖重写了接口的默认方法");
                }
            }
        备注：
            学习到蓝布达表达式和函数式编程，接口的默认方法可以拼接函数模型
    静态方法
        从Java 8开始，接口当中允许定义静态方法
        格式：
            public static 返回值类型 方法名称(参数列表){
                方法体
            }
        提示：就是将abstract或者default换成static即可，戴上方法体
        注意事项：
            1.不能通过接口实现类的对象来调用接口当中的静态方法
            2.静态方法跟对象没有关系，跟类有关系
        用法：通过接口名称，直接调用其中的静态方法
        格式：
            接口.静态方法名(参数)
    私有方法
        问题描述
            可以抽取一个共有方法，用来解决两个默认方法之间重复代码的问题
            但是这个共有方法不应该让实现类使用，应该私有化
        解决方案：
            从Java 9开始，接口当中允许定义私有方法
            1.普通私有方法，解决多个默认方法之间重复代码问题
                格式：private 返回值类型 方法名称(参数列表){
                    方法体
                }
            2.静态私有方法，解决多个静态方法之间重复代码问题
                格式：private static 返回值类型 方法名称(参数列表){
                    方法体
                }
    常量
        接口当中也可以定义“成员变量”，但是必须使用public static final三个关键字进行修饰
        从效果上看，这其实就是接口的【常量】
        格式：
            public static final 数据类型 常量名称 = 数据值;
        备注：
            一旦使用final关键字进行修饰，说明不可改变
        注意事项：
            1.接口当中的常量，可以省略public static final，注意：不写也照样是这样
            2.接口当中的常量，必须进行赋值；不能不赋值
            3.接口中常量的名称，使用完全大写的字母，用下划线分隔（推荐命名规则）
        使用：
            接口名称.常量
    接口内容小结
        在Java 9+版本中，接口内容可以有：
        1.成员变量其实是常量，格式：
        [public] [static] [final] 数据类型 常量名称 = 数据值

        2.接口中最重要的就是抽象方法，格式：
        [public] [abstract] 返回值类型 方法名称(参数列表)
        注意：实现类必须覆盖重写接口所有的抽象方法，除非实现类是抽象类

        3.从Java 8开始，接口里允许定义默认方法，格式：
        [public] default 返回值类型 方法名称(参数列表){方法体}

        4.从Java 8开始，接口里允许定义静态方法，格式：
        [public] static 返回值类型 方法名称(参数列表){方法体}
        
        5.从Java 9开始，接口里允许定义私有方法，格式：
        普通私有方法：private 返回值类型 方法名称(参数列表){方法体}
        静态私有方法：private static 返回值类型 方法名称(参数列表){方法体}
        注意：private的方法只有接口自己才能调用，不能被实现类或者别人使用
    使用接口时，需要注意：
        1.接口是没有静态代码块或者构造方法的
        2.一个类的直接父类是唯一的，但是一个类可以同时实现多个接口
        格式：
        public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
            // 覆盖重写所有抽象方法
        }
        3.如果实现类所实现的多个接口当中，存在重复的抽象方法，那么只需要覆盖重写一次即可
        4.如果实现类没有覆盖重写所有接口当中的所有抽象方法，那么实现了就必须是一个抽象类
        5.如果实现类所实现的多个接口当中，存在重复的默认方法，那么实现类一定要对冲突的默认方法进行覆盖重写
        6.一个类如果直接父类当中的方法，和接口当中的默认方法产生了冲突，优先用父类当中的方法
    接口之间的多继承
        1.类与类之间是单继承的，直接父类只有一个
        2.类与接口之间是多实现的，一个类可以实现多个接口
        3.接口与接口之间是多继承的
        注意事项：
            1.多个父接口当中的抽象方法如果重复，没关系
            2.多个父接口当中的默认方法如果重复，那么子接口必须进行默认方法的覆盖重写（而且带着default关键字）
    面向对象三大特征：封装性、继承性、多态性
        extends继承或者implements实现，是多态性的前提
        多态性
            代码当中体现多态性，其实就是一句话：父类引用指向子类对象
            格式：
                父类名称 对象名 = new 子类名称()
            或者：
                对象名 对象名 = new 实现类名称()
        访问成员变量的两种方式：
            1.直接通过对象名称访问成员变量：看等号左边是谁，优先用谁，没有则向上找
            2.间接通过成员方法访问成员变量：看该方法属于谁，优先用谁，没有则向上找
                1.子类没有覆盖重写,就找父
                2.子类如果覆盖重写,就找子
            public class Fu{
                int num = 10
                public void method(){
                    System.out.println(num);
                }
            }
            public class Zi extends Fu{
                int num = 20
                // @Overrride
                // public void method(){
                //     System.out.println(num);
                // }
            }
            public class App{
                public static void main(String[] args){
                    Fu zi = new Zi();
                    zi.num;//10
                    // 子类没有覆盖重写,就是父 10
                    // 子类如果覆盖重写,就是子 20
                    zi.method();//10
                }
            }
    对象向上转型，其实就是多态写法
        Animal animal = new Cat();
        格式：父类名称 对象名 = new 子类名称();
        含义：右侧创建一个子对象，把它当做父类来看待使用
        注意事项：向上转型一定是安全的，从小范围转向了大范围，从小范围的猫，想上转换成为更大范围的动物
        类似于：
            double num = 100;//正确 int-->double，自动类型转换
    对象向下转型，其实是一个【还原】的动作
        格式：子类名称 对象名 = (子类名称)父类对象;
        含义：将父类对象，【还原】成为本来的子类对象
        Animal animal = new Cat();//本来是猫，向下转型成为动物
        Cat cat = (Cat) animal;//本来是猫，已经被当做动物了，还原回来成为本来的猫
        注意事项：
            a.必须保证对象本来创建的时候，就是猫，才能向下转型成为猫
            b.如果对象创建的时候本来不是猫，现在非要向下转型成为猫，就会报错 ClassCastException
    instanceof
        格式：
            对象 instanceof 类名称
            这将会得到一个booleann值结果，也就是判断前面的对象能不能当做后面类型的实例
        如果希望调用子类特有方法，需要向下转型
        public static void main(String[] args){
            Animal animal = new cat();
            animal.eat();
            giveMeAPet(new Dog());
        }
        public static void giveMeAPet(Animal animal){
            if(animal instanceof Dog){//判断传进的对象属于哪个子类
                Dog dog = (Dog) animal;
                dog.watchHouse();
            }
            if(animal instanceof Cat){
                Cat cat = (Cat) animal;
                cat.catchMouse();
            } 
        }
    接口案例
        public static void main(String[] args){
            computer.powerOn();//开机

            USB usbMouse = new Mouse();//多态写法
            // 参数是USB类型，我正好传递进去的就是USB鼠标
            computer.useDevice(usbMouse);

            // 创建一个USB键盘
            Keyboard keyboard = new Keyboard();
            computer.useDevice(keyboard);//正确写法 也发生了向上转型
            computer.useDevice(new Keyboard());//也是正确写法

            computer.powerOff();//关机

            method(10.0);// 正确写法 double --> double
            method(10);//正确写法 int --> double
        }
        public static void method(double num){
            System.out.println(num);
        }
    final
        可以修饰类、方法、局部变量、成员方法 
        1.当final关键字用来修饰一个类的时候
            格式：
                public final class 类 {
                }
            含义：当前这个类不能有任何的子类（太监类）
            注意：一个类如果是final的，那么其中的成员方法都无法进行覆盖重写（因为没儿子）
        2.当final关键字修饰一个方法的时候，这个方法就是最终方法，也就是不能被覆盖重写
            格式：
                修饰符 final 返回值类型 方法名称(参数列表){
                }
            注意：对于类、方法来说，abstract关键字和final关键字不能同时使用，因为矛盾
        3.一旦使用final修饰局部变量，那么变量就不能进行更改
            对于基本类型来说，不可变说的是变量当中的数据不可改变
            对于引用数据来说，不可变说的是变量当中的地址不可改变
        4.对于成员变量来说，如果使用final关键字修饰，那么这个变量也照样不可变
            1.由于成员变量具有默认值，所以用了final之后必须手动赋值，不会再给默认值了
            2.对于final的成员变量，要么使用直接赋值，要么通过构造方法赋值，二者选一
            3.必须保证类当中所有重载的构造方法，都是最终会对final的成员变量进行赋值
    Java中有四种权限修饰符：
                                public  >  protected  >  (default)  >  private
        同一个类（我自己）         YES         YES           YES           YES
        同一个包（我邻居）         YES         YES           YES           NO
        不同包子类（我儿子）       YES         YES           NO            NO
        不同包非子类（我邻居）     YES         NO            NO            NO
    成员内部类
        定义格式：
        修饰符 class 外部类名称 {
            修饰符 class 内部类名称 {
                
            }
        }
        内部类的同名变量访问
            public class Outer {
                int num = 10;
                public class Inner{
                    int num = 20;
                    public void methodInner(){
                        int num = 30;
                        System.out.println(num);
                        System.out.println(this.num);
                        System.out.println(Outer.this.num);//访问外部类,加个类作为前缀即可
                    }
                }
            }
        如何使用成员内部类，有两种方式
        1.间接方式：在外部类的方法当中，使用内部类；然后main只是调用外部类的方法
        2.直接方式：公式：
            类名称 对象名 = new 类名称
            【外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();】
    局部内部类（包含匿名内部类）
        如果一个类是定义在一个方法内部的，那么这就是一个局部类
        “局部”：只有当前所属的方法才能使用它，出了这个方法外面就不能用了
        定义格式：
            修饰符 class 外部类名称{
                修饰符 返回值类型 外部类方法名称(参数列表){
                    class 局部内部类 {
                        ...
                    }
                }
            }
    定义一个类的时候，权限修饰符规则
        1.外部类：public / (default)
        2.成员内部类：public / protected / (default) / private
        3.局部内部类：什么都不能写
    局部内部类的final问题
        如果希望访问所在方法的局部变量，那么这个局部变量必须是【有效final的】
        备注：从Java 8+开始，只要局部变量事实不变，那么final关键字可以省略
        原因：
            1.new出来的对象在堆内存当中
            2.局部变量是跟着方法走的，在栈内存当中
            3.方法运行结束后，立刻出栈，局部变量就会立刻消失
            4.但是new出来的对象会在堆当中持续存在，直到垃圾回收消失
        示例
            public class Outer {
                public void methodOuter(){
                    int num = 10;//所在方法的局部变量
                    class Inner {
                        public void methodInner(){
                            System.out.println(num);
                        }
                    }
                }
            }
    匿名内部类（重点）
        接口名称 对象名 = new 接口名称(){
            //覆盖重写所有抽象方法
        }
        对格式“new 接口名称(){...}”进行解析：
        1.new代表创建对象的动作
        2.接口名称就是匿名内部类需要实现哪个接口
        3.{...}这才是匿名内部类的内容
        另外还要注意几点问题：
        1.匿名内部类，在【创建对象】的时候，只能使用唯一一次。
        如果希望多次创建对象，而且类的内容一样的话，那么必须使用单独定义的实现类了
        2.匿名对象，在【调用方法】的时候，只能调用唯一一次
        如果希望同一个对象，调用多次方法，那么必须给对象起个名字
        3.匿名内部类是省略了【实现类/子类名称】，但是匿名对象是省略了【对象名称】
        强调：匿名内部类和匿名对象不是一回事
        例：
            MyInterface obj = new MyInterface(){
                @override
                public void method(){
                    System.out.println("匿名内部类实现了方法！");
                }
            }
            obj.method();//匿名内部类实现了方法！
    类作为成员变量类型
        public static void main(String[] args){
            // 创建英雄角色
            Hero hero = new Hero();
            // 给英雄起名字
            hero.setName("盖伦");
            // 创建一个武器
            Weapon weapon = new Weapon("多兰剑");
            // 把武器给英雄
            Hero.setWeapon(weapon);
            // 英雄进行攻击
            Hero.attack();//盖伦使用多兰剑攻击敌方
        }
        public class Hero{
            private String name;
            private Weapon weapon;
            public void setName(name){
                this.name = name;
            }
            public void setWeapon(weapon){
                this.weapon = weapon;
            }
            public void attack(){
                System.out.println(name+'使用'+weapon.getCode()+"攻击敌方");
            }
        }
        public class Weapon{
            private String code;
            public String getCode(){
                return this.code;
            }
            public void setCode(code){
                this.code = code
            }
        }
    接口作为成员变量类型(大体东西同上)
        把new实现类出来的对象当参数传
    object类
        toString
            1.直接打印对象其实就是调用对象的toString方法
            2.看一个类有没有重写toString,只需要打印这个类的对象,如果没有重写打印的就是地址值
    装箱和拆箱
        装箱
            从基本类型转换为对应的包装类对象
            Integer i = new Integet(4);//使用构造方法函数
            Interget ii = Integer.valueOf(4);//使用包装类中的valueOf方法
        拆箱
            从包装类对象转换为对应的基本数据类型
            int num = i.intValue()
    自动装箱和自动拆箱
        获取时自定拆箱,用完时自动装1箱,步骤无需自行操作
    迭代器
        ArrayList list new ArrayList();
        list.add("abc")；
        list.add(1);
        // 使用迭代器遍历list集合
        // 获取迭代器
        Iterator it = list.iterator();
        // 使用迭代器中的方法hasNext和next遍历集合
        while(it.hasNext()){
            // 取出元素也是Object类型
            Object obj = it.next();
            System.out.println(obj);

            // 想要使用String类特有的方法,length获取字符串的长度,不能使用多台 Object obj = 'abc'
            // 需要向下转型
            // 会抛出ClassCastException类型转换异常,不能把Integet类型转换为String类型
            String s = (String)obj;
            System.out.println(s.length());
        }
    泛型
        不确定要使用什么类型时,使用泛型
        创建集合类型,不使用泛型
            好处
                1.集合不使用泛型,默认的类型就是Object类型,可以存储任意类型的数据
                2.把运行期异常(代码运行之后会抛出异常),提升到了编译期(写代码的时候会报错)
            弊端
                不安全,会引发异常
        创建集合对象,使用泛型
            好处
                避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
            弊端
                泛型是什么类型,只能存储什么类型的数据
        定义含有的泛型方法: 泛型定义在方法的修饰符和返回值类型之间
            格式：
                修饰符 <泛型> 返回值 方法名(参数列表(使用泛型)){
                    方法体;
                }
            含有泛型的方法,在调用方法的时候确定泛型的数据类型
            传递什么类型的参数,泛型就是什么类型
            public class GenericMethod{
                定义一个含有泛型的方法
                public <M> void method01(M m){
                    System.out.println(m);
                }
                public static <S> void method02(S m){
                    System.out.println(m);
                }
            }
            public static void main(String[] args){
                GenericMethod gm = new GenericMethod();
                gm.method01(10);
                gm.method01("abc");
                gm.method01(8.8);
                gm.method01(true);
                gm.method02("静态方法不建议创建对象使用")
                // 静态方法,通过类名.方法名(参数)可以直接使用
                GenericMethod.method02("静态方法");
                GenericMethod.method02(1);
            }
        定义含有泛型的接口
            含有泛型的接口第一种使用方式(定义接口的实现类，实现接口时指定泛型)
            public interface GenericInterImpl1 implements GenericInterface<String>{
                @Override
                public void method(String i){
                    System.out.println(i);
                }
            }
            含有泛型的接口第二种使用方式
                (接口使用什么泛型，实现类就使用什么泛型，就相当于定义了一个含有泛型的类，创建对象时确定泛型的类型)
            public class GenericInterfaceImpl2<I> implements GenericInterface<I>{
                @Override
                public void method(I i){
                    System.out.println(i);
                }
            }
            定义含有泛型的接口
            public interface GenericInterface<I>{
                public abstract void method(I i);
            }
            测试含有泛型的接口
            public class DemoMain{
                public static void main(String[] args){
                    //创建1对象
                    GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
                    gi1.method("字符串");

                    //创建2对象
                    GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
                    gi2.method(8);
                    
                    //创建2对象
                    GenericInterfaceImpl2<Double> gi2 = new GenericInterfaceImpl2<>();
                    gi2.method(8.8);

                }
            }
        泛型通配符
            ?:代表任意的数据类型
            使用方式
                不能创建对象使用
                只能作为方法的参数使用
            注意：泛型没有继承概念
            public class App{
                public static void main(String[] args){
                    ArrayList<Integer> list1 = new ArrayList<>();
                    list1.add(1);
                    list1.add(2);
                    
                    ArrayList<String> list2 = new ArrayList<>();
                    list2.add("a");
                    list2.add("b");

                    printArray(list1);
                    printArray(list2);
                }
                // 定义一个方法,能遍历所有类型的ArrayList集合
                // 这时候我们不知道ArrayList集合使用什么数据类型，可使用泛型的通配符?磊接受数据类型
                public static void printArray(ArrayList<?> list){
                    // 使用迭代器遍历集合
                    Iterator<?> it = list.iterator();
                    while(it.hasNext()){
                        it.next()方法,取出来的元素是Object,可以接收任意的数据类型
                        System.out.println(it.next());
                    }
                }
            }
        泛型通配符高级使用-受限泛型
            泛型的上限限定：? extends E 代表使用的泛型只能是E类型的子类/本身
            泛型的下限限定：? super    E 代表使用的泛型只能是E类型的父类/本身
            

            
*/
</script>
<script>
    // 2020.03.23 第79集
    // 2020.04.22 知道了默认方法，静态方法，私有方法
    // 2020.05.27 第207集 
    // 2021.01.20 第169集 重新学习了继承概念 抽象类
    // 2021.01.27 第183集 继承写发红包案例 接口实现/默认方法/静态方法/私有方法/常量
    // 2021.01.28 第188集 接口多继承 多态性
    // 2021.02.02 第200集 USB接口案例 对象的向上向下转型/final修饰符
    // 2021.02.03 第211集 成员内部类/局部内部类/匿名内部类 类/接口作为成员变量类型
    // 2021.03.10 第216集 Object类的toString方法
    // 2021.04.02 第246集 泛型 不急哈

// 哔哩哔哩
    // SiKi
    // 01，《Java编程学习第一季》：av35556299
    // 02，《Java编程学习第二季》：av37316788
    // 03，《Java编程学习第三季》：av37317551
    // 04，《Java编程学习第四季》：av38308449
    // 05，《JDBC编程和MySQL数据库》：av37325712
    // 06，《Web前端第一季（HTML）》：av35875257
    // 07，《Web前端第三季（JavaScript）》：av37383464
    // 08，《Web前端第四季（JQuery）》：av38513367
    // 09，《JavaWeb第一季基础（JSP和Servlet）》：av37398251
    // 10，《JavaWeb第二季进阶》：av37398729
    // 11，《3小时学会使用Maven构建项目》：av38517296
    // 12，《SSH框架第一季 - Struts入门》：av38472605
    // 13，《SSH框架第二季 - Hibernate入门》：av38476142
    // 14，《SSM框架第一季 - Mybatis入门》：av38513367
    // 15，《SSM框架第二季 - Spring入门》：av38516969
    // 16，《Spring Boot快速入门》：av38356979
    // 17，《手把手教你使用Cropper》：av38512574

    // 重要的事
</script>
</html>